package com.travel.search.service.Impl;

import com.alibaba.fastjson.JSON;
import com.travel.common.es.TicketEsModel;
import com.travel.search.config.TravelElasticsearchConfig;
import com.travel.search.constant.EsConstant;
import com.travel.search.service.TravelTicketSearchService;
import com.travel.search.vo.SearchAttractionResult;
import com.travel.search.vo.SearchTicketParam;
import com.travel.search.vo.SearchTicketResult;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;


@Service
public class TravelTicketSearchServiceImpl implements TravelTicketSearchService {

    @Autowired
    RestHighLevelClient esRestClient;

    /**
     * @param param ：所有的查询条件·和过滤条件
     * @return
     */
    @Override
    public SearchTicketResult search(SearchTicketParam param) {
        //1. 动态构建出查询需要的DSL语句
        SearchTicketResult result = null;

        //2. 准备检索请求的DSL语句
        SearchRequest searchRequest = buildSearchTicketDSL(param);


        try{
            //3. 执行检索请求
            SearchResponse response = esRestClient.search(searchRequest, TravelElasticsearchConfig.COMMON_OPTIONS);

            //4. 分析响应的数据，封装成我们需要的格式
            result = buildSearchResult(response,param);
        }catch (IOException e){
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 构建DSL语句
     * 模糊匹配，排序，分页，高亮
     * 过滤（按照各种属性），聚合分析功能
     * @param param
     * @return
     */
    private SearchRequest buildSearchTicketDSL(SearchTicketParam param) {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); //构建DSL语句的

        //1. 构建bool - query
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        //1.1 bool - must 模糊匹配 spuName
        if(!StringUtils.isEmpty(param.getKeyword())){
            boolQuery.must(QueryBuilders.matchQuery("spuName",param.getKeyword()));
        }

        //1.2 bool - filter 按照省份过滤
        if(!StringUtils.isEmpty(param.getLocation())){
            boolQuery.filter(QueryBuilders.termQuery("location",param.getLocation()));
        }

        //1.3 bool - filter 按照票的类型过滤
        if(!StringUtils.isEmpty(param.getType())){
            boolQuery.filter(QueryBuilders.termQuery("type",param.getType()));
        }

        //把以前所有的条件都拿来进行封装
        sourceBuilder.query(boolQuery);

        /**
         * 排序，分页，高亮
         */
        //2.1 排序
        if(!StringUtils.isEmpty(param.getSort())){
            //例：sort=price_asc/desc
            String sort = param.getSort();
            String[] s = sort.split("_"); //s[0]:排序字段 s[1]:asc/desc
            SortOrder order = s[1].equalsIgnoreCase("asc")?SortOrder.ASC:SortOrder.DESC;
            sourceBuilder.sort(s[0],order);
        }

        //2.2 分页 pageSize pageNum from from=(pageNum-1)*pageSize
        sourceBuilder.from((param.getPageNum()-1) * EsConstant.PRODUCT_PAGESIZE);
        sourceBuilder.size(EsConstant.PRODUCT_PAGESIZE);

        //2.3 高亮
        if(!StringUtils.isEmpty(param.getKeyword())){
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.field("spuName");
            highlightBuilder.preTags("<b style='color:red'>");
            highlightBuilder.postTags("</b>");
            sourceBuilder.highlighter(highlightBuilder);
        }

        System.out.println("构建的DSL语句=="+sourceBuilder.toString());


        SearchRequest searchRequest = new SearchRequest(new String[]{EsConstant.TICKET_INDEX}, sourceBuilder);
        return searchRequest;
    }

    /**
     * 构建结果数据
     * @param response
     * @param param
     * @return
     */
    public SearchTicketResult buildSearchResult(SearchResponse response,SearchTicketParam param){
        SearchTicketResult result = new SearchTicketResult();

        //1. 返回所有查询到的票务信息
        SearchHits hits = response.getHits();
        List<TicketEsModel> esModels = new ArrayList<>();
        if(hits.getHits()!=null && hits.getHits().length>0){
            for(SearchHit hit : hits){
                // 为票务信息
                String sourceAsString = hit.getSourceAsString();
                // 转为票对象
                TicketEsModel esModel = JSON.parseObject(sourceAsString, TicketEsModel.class);
                // 设置检索词高亮
                if(!StringUtils.isEmpty(param.getKeyword())){
                    HighlightField spuName = hit.getHighlightFields().get("spuName");
                    String string = spuName.getFragments()[0].string();
                    esModel.setSpuName(string);
                }
                esModels.add(esModel);
            }
        }
        result.setTickets(esModels);

        //3. 分页信息 - 页码
        result.setPageNum(param.getPageNum());

        //4. 分页信息 - 总记录数
        long total = hits.getTotalHits().value;
        result.setTotal(total);

        //4. 分页信息 - 总页码
        int totalPages = (int)total%EsConstant.PRODUCT_PAGESIZE == 0?(int)total/EsConstant.PRODUCT_PAGESIZE:(int)total/EsConstant.PRODUCT_PAGESIZE+1;
        result.setTotalPages(totalPages);

        //设置检索的关键词
        if(param.getKeyword()!=null){
            result.setKeyword(param.getKeyword());
        }else{ //无检索关键词，即点击省份跳转的
            result.setKeyword(param.getLocation());
        }

        return result;
    }
}
